#ifndef _SERVER_UDP_HPP_
#define _SERVER_UDP_HPP_

#include <iostream>
#include <unordered_map>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cerrno>
#include <cstdbool>
#include <cassert>
#include <strings.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

class ServerUDP
{
    static const int SIZE;
private:
    int _sockfd;
    uint16_t _port;
    std::string _ip;
    std::unordered_map<std::string,struct sockaddr_in> _stringMap;
public:
    ServerUDP(uint16_t port,const std::string &ip="0.0.0.0")
        :_sockfd(0),_port(port),_ip(ip)
    {}

    ~ServerUDP()
    {}

    bool init()
    {
        // 1.创建网络套接字
        _sockfd=socket(AF_INET,SOCK_DGRAM,0);
        if(_sockfd<0)
        {
            std::cerr<<"socket error"<<std::endl;
            return false;
        }
        //std::cout<<"_sockfd: "<<_sockfd<<std::endl;

        // 2.进行绑定
        // 2.1 sockaddr_in的属性设置
        struct sockaddr_in local;
        memset(&local,0,sizeof(local)); // bzero
        local.sin_family=AF_INET;
        local.sin_port=htons(_port);
        local.sin_addr.s_addr=inet_addr(_ip.c_str());

        socklen_t localLen=sizeof(local);

        // 2.2 调用bind
        if(bind(_sockfd,(struct sockaddr*)&local,localLen)<0)
        {
            std::cerr<<"bind error"<<std::endl;
            close(_sockfd);
            return false;
        }

        return true;
    }

    void start()
    {
        char buff[SIZE];
        struct sockaddr_in peer;
        memset(&peer,0,sizeof(peer));

        socklen_t peerLen=sizeof(peer);

        while(true)
        {
            // 1.获取数据
            ssize_t n=recvfrom(_sockfd,(void *)buff,sizeof(buff)-1,0,(struct sockaddr*)&peer,&peerLen);
            assert(n>=0);
            buff[n]='\0';

            // 2.进行分析
            char key[64];
            bzero((void *)key,sizeof(key));
            std::string peer_ip=inet_ntoa(peer.sin_addr);
            uint16_t peer_port=ntohs(peer.sin_port);

            snprintf(key,sizeof(key)-1,"%s:%d",peer_ip.c_str(),peer_port);

            std::string keyStr(key);
            if(_stringMap.find(keyStr)==_stringMap.end())
            {
                // keyStr不在_stringMap则进行保存
                _stringMap.insert({keyStr,peer});
            }
            // 3.返回数据
            std::string message(key);
            message+="# ";
            message+=buff;
            for(auto &iter:_stringMap)
            {
                sendto(_sockfd,message.c_str(),message.size(),0,(struct sockaddr *)&iter.second,sizeof(iter.second));
            }
        }
    }
};
const int ServerUDP::SIZE=1024;

#endif